﻿using System;
using System.IO;
using System.Text;

namespace ZFramework.Runtime
{
    public class NetworkChannelHelper : INetworkChannelHelper
    {
        private INetworkChannel _mNetworkChannel = null;

        private ByteBuffer _writer;
        private ByteBuffer _body;

        /// <summary>
        /// 获取消息包头长度,网络框架底层会用到
        /// </summary>
        public int PacketHeaderLength
        {
            get
            {
                return sizeof(int);
            }
        }

        public void Initialize(INetworkChannel networkChannel)
        {
            _mNetworkChannel = networkChannel;
            //_mNetworkChannel.SetDefaultHandler(RouteS2C);
            _writer = new ByteBuffer();
            _body = new ByteBuffer();
        }

        public void Shutdown()
        {
            _writer?.Close();
            _body?.Close();
        }

        public void PrepareForConnecting()
        {
            _mNetworkChannel.Socket.ReceiveBufferSize = 1024 * 64;
            _mNetworkChannel.Socket.SendBufferSize = 1024 * 64;
        }

        public bool SendHeartBeat()
        {
            return true;
        }
        
        public bool Serialize<T>(T packet, Stream destination) where T : Packet
        {
            var packetC2S = packet as PacketC2S;
            if (packetC2S == null)
                return false;

            var reqId = packetC2S.ReqId;
            var msgName = packetC2S.MsgName;
            var data = packetC2S.Data;
            _body.stream.SetLength(0);
            _body.WriteInt(reqId);
            _body.WriteString(msgName);
            _body.WriteRawBytes(data);
            
            _writer.stream.SetLength(0);
            byte[] bodyBytes = _body.ToBytes();
            _writer.WriteInt(bodyBytes.Length);
            _writer.WriteRawBytes(bodyBytes);
            _writer.Flush();

            using (BinaryWriter writer = new BinaryWriter(destination, Encoding.UTF8, true))
            {
                writer.Write(_writer.ToBytes());
            }
            destination.Flush();
            return true;
        }

        public IPacketHeader DeserializePacketHeader(Stream source, out object customErrorData)
        {
            using (BinaryReader reader = new BinaryReader(source, Encoding.UTF8, true))
            {
                // 从流中先读取包长度
                Int32 length = NetUtils.NetworkToHostOrder_Int32(reader.ReadBytes(4));
              
                // 手动赋值PacketHeader
                var header = ReferencePool.Acquire<PacketS2CHeader>();
                header.PacketLength = length;
                customErrorData = header;
                return header;
            }
        }

        public Packet DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData)
        {
            var header = packetHeader as PacketS2CHeader;
            var packetLength = header.PacketLength;
            if (header == null)
            {
                throw new Exception("header类型不是PacketS2CHeader");
            }

            ReferencePool.Release(header);
            // 注意：此函数并不在主线程调用！
            customErrorData = null;
            
            // 使用 BinaryReader 从流中读取数据
            PacketS2C packet = null;
            using (BinaryReader reader = new BinaryReader(source, Encoding.UTF8, true))
            {
                var gzipped = reader.ReadByte();
                var message = reader.ReadBytes(packetLength - 1);
                if (gzipped == 1)
                {
                    message = NetUtils.UnzipBytes(message);
                }

                using (MemoryStream messageStream = new MemoryStream(message))
                {
                    using (BinaryReader messageReader = new BinaryReader(messageStream, Encoding.UTF8, true))
                    {
                        var packetId = messageReader.ReadInt32();
                        packet = PacketS2C.Create(packetId);
                        for (; messageStream.Position < messageStream.Length;)
                        {
                            var len = NetUtils.NetworkToHostOrder_Int32(messageReader.ReadBytes(4));
                            var reqId = NetUtils.NetworkToHostOrder_Int32(messageReader.ReadBytes(4));
                            var stringLength = NetUtils.NetworkToHostOrder_UInt16(messageReader.ReadBytes(2));
                            var stringBuffer = messageReader.ReadBytes(stringLength);
                            var msgName = Encoding.UTF8.GetString(stringBuffer);
                            var data = messageReader.ReadBytes(len);
                            var msg = PacketMessage.Create(reqId, msgName, data);
                            packet.AddMessage(msg);
                        }
                    }
                }

                return packet;
            }
        }
    }
}